package com.tsfyun.scm.util;

import cn.hutool.core.util.ClassUtil;
import com.google.common.collect.Lists;
import com.tsfyun.common.base.enums.RespCodeEnum;
import com.tsfyun.common.base.enums.ResultCodeEnum;
import com.tsfyun.common.base.enums.WxMessageDefineTemplate;
import com.tsfyun.common.base.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 枚举工具类
 * add by rick at 2020-03-06
 */
public class EnumUtils {

    private static Logger logger = LoggerFactory.getLogger(EnumUtils.class);

    private static Map<String,List<Map<String,Object>>> enumMaps = new ConcurrentHashMap();//枚举类数据集合

    private static final String ENUM_PACKAGE_PATH = "com.tsfyun.common.base.enums";//枚举类包路径

    private static final String GET_CODE_METHOD_NAME = "getCode";

    /**
     * 不扫描的枚举类
     */
    private static final List<String> excludeScan = new ArrayList<String>() {{
        add(ResultCodeEnum.class.getSimpleName());
        add(RespCodeEnum.class.getSimpleName());
        add(WxMessageDefineTemplate.class.getSimpleName());
    }};

    private Lock lock = new ReentrantLock();

    /**
     * 构造方法
     */
    private EnumUtils(){

    }

    //单例模式
    private static EnumUtils instance;

    public static EnumUtils getInstance(){
        if (instance == null) {
            synchronized (EnumUtils.class) {
                if (instance == null) {
                    instance = new EnumUtils();
                }
            }
        }
        return instance;
    }


    public static void main(String[] args) throws Exception{
        Map<String,List<Map<String,Object>>> dictMap = EnumUtils.getInstance().getData();
        System.out.println(dictMap);
    }

    /**
     * 获取枚举数据map
     * @return
     */
    public Map<String,List<Map<String,Object>>> getData() {
        if(enumMaps != null && !enumMaps.isEmpty()) {
            return enumMaps;
        }
        lock.lock();//加锁，防止并发重复写
        try {
            //#######################读取某个包及子包下面的所有枚举类#############
            logger.info("扫描包{}下面的所有枚举类", ENUM_PACKAGE_PATH);
            Set<Class<?>> classes = ClassUtil.scanPackage(ENUM_PACKAGE_PATH);
            //######################遍历所有的枚举类##########################
            if (classes != null && classes.size() > 0) {
                for (Class clazz : classes) {
                    if(excludeScan.contains(clazz.getSimpleName())) {
                        continue;
                    }
                    List<Map<String, Object>> list = getEnumValueByClass(clazz);
                    enumMaps.put(clazz.getSimpleName().replace("Enum","").replace("enum",""), list);
                }
            }
        } finally {
            lock.unlock();//解锁
        }
        return enumMaps;
    }

    public static List<Map<String,Object>> getEnumValueByClass(Class tt) {
        List<Map<String,Object>> list = Lists.newArrayList();
        //获取枚举里面的字段
        Object[] objects = tt.getEnumConstants();
        try {
            Method getCode = tt.getMethod("getCode");
            Method getName = tt.getMethod("getName");
            Map<String, Object> map = null;
            for (Object object : objects) {
                map = new HashMap();
                map.put("value", getCode.invoke(object));
                map.put("label", getName.invoke(object));
                list.add(map);
            }
        } catch (Exception e) {
            logger.error("获取枚举信息异常",e);
        }
        return list;
    }

    /**
     * 判断数值是否属于枚举类的值
     * @param value
     * @return
     */
    public boolean isInclude(Class clazz,String value){
        boolean include = false;
        if(clazz ==  null || !clazz.isEnum()) {
            return false;
        }
        Object[] objs = clazz.getEnumConstants();
        for (int i = 0; i < objs.length; i++) {
            try {
                Method m = clazz.getMethod(GET_CODE_METHOD_NAME);
                String invokeValue = StringUtils.null2EmptyWithTrim(m.invoke(objs[i]));
                if (value.equals(invokeValue)) {
                    return true;
                }
            } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                return false;
            }
        }
        return include;
    }

}
